import math
import types

class Vector2(object):
    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)

    def __str__(self):
        return "(%f,%f)"%(self.x, self.y)
    
    def __neg__(self):
        return Vector2(-self.x, -self.y)
    
    def __add__(self, other):
        return Vector2(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Vector2(self.x - other.x, self.y - other.y)
    
    def __mul__(self, other):
        if (type(other) == types.IntType):
            other = float(other)
        if (type(other) == types.FloatType):
            return Vector2(self.x * other, self.y * other)
        else:
            return Vector2(self.x * other.x, self.y * other.y)
    
    def __rmul__(self, other):
        return self.__mul__(other)
    
    def __div__(self, other):
        if (type(other) == types.IntType):
            other = float(other)
        if (type(other) == types.FloatType):
            return Vector2(self.x / other, self.y / other)
        else:
            return Vector2(self.x / other.x, self.y / other.y)
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def _GetTuple(self):
        return (self.x, self.y)
    
    tuple = property(_GetTuple)
    
    def _GetIntTuple(self):
        return (int(self.x), int(self.y))
    
    int_tuple = property(_GetIntTuple)

    def _GetLength(self):
        return math.sqrt(self.x*self.x + self.y*self.y)
    
    length = property(_GetLength)
    
    # returns a new vector
    def Unit(self):
        length = self.length

        if (length == 0.0):
            return Vector2(self.x, self.y)
        else:
            return Vector2(self.x / length, self.y / length)

    # normalizes this vector
    def Normalize(self):
        length = self.length
        if (length == 0.0):
            return
        self.x /= length
        self.y /= length

    def Flip(self):
        return -self

    def YFlip(self, max_y):
        return Vector2(self.x, float(max_y) - self.y)

    def Perp(self):
        return Vector2(-self.y, self.x)


def Dot(vec1, vec2):
    return (vec1.x * vec2.x) + (vec1.y * vec2.y)


def CrossMag(vec1, vec2):
    return (vec1.x * vec2.y) - (vec1.y * vec2.x)


def Distance(p1, p2):
	return (p1 - p2).length


def PointLineDistance(p, l1, l2):
	return ((l1.y-l2.y)*p.x + (l2.x-l1.x)*p.y + (l1.x*l2.y - l2.x*l1.y)) / math.sqrt((l2.x-l1.x)*(l2.x-l1.x) + (l2.y-l1.y)*(l2.y-l1.y))


def PointSegmentDistance(p, l1, l2):
	l_direction = subtract( l2, l1 ).Unit()
	p_projected = add( l1, multiply( dot( l_direction, p ), l_direction ) )
	t = subtract( p_projected, l1 ).length / subtract( l2, l1 ).length

	# if p is beyond l1, return distance to l1
	if( t < 0.0 ):
		return Distance( p, l1 )

	# if p is beyond l2, return distance to l2
	elif( t > 1.0 ):
		return Distance( p, l2 )

	# if p is between l1 and l2, return the point line distance
	else:
		return PointLineDistance( p, l1, l2 )


def LineIntersection(p1, p2, q1, q2):
	u = subtract(p2, p1)
	v = subtract(q2, q1)

	perp_dot_product = (u.x * v.y) - (u.y * v.x)
	if (perp_dot_product == 0.0):
		return None

	w = subtract(p1, q1)
	s = ((v.y * w.x) - (v.x * w.y)) / (-perp_dot_product)
	intersection = add(p1, multiply(s, u))

	return intersection
    
    
class Rect2(object):
    def __init__(self, left, bottom, width, height):
        self.left = float(left)
        self.bottom = float(bottom)
        self.width = float(width)
        self.height = float(height)
        
    def __str__(self):
        return "(%f,%f,%f,%f)"%(self.left, self.bottom, self.width, self.height)
        
    def Contains(self, p):
        left_right = [self.left, self.right]
        left_right.sort()
        left, right = left_right
        bottom_top = [self.bottom, self.top]
        bottom_top.sort()
        bottom, top = bottom_top
        return (p.x >= left and p.x <= right and
                p.y >= bottom and p.y <= top)
    
    def Translate(self, t):
        self.left += t.x
        self.bottom += t.y
        
    def Scale(self, s):
        self.left *= s
        self.bottom *= s
        self.width *= s
        self.height *= s
        
    def ScaleAboutCenter(self, s):
        center = self.center
        self.Translate(-center)
        self.Scale(s)
        self.Translate(center)
    
    def _GetLeftBottom(self):
        return Vector2(self.left, self.bottom)

    left_bottom = property(_GetLeftBottom)
    
    def _GetCenter(self):
        return Vector2(self.left + (self.width / 2.0), self.bottom + (self.height / 2.0))
    
    center = property(_GetCenter)
    
    def _GetRight(self):
        return self.left + self.width
    
    right = property(_GetRight)
    
    def _GetTop(self):
        return self.bottom + self.height
    
    top = property(_GetTop)
    
    
def RectTransform(point, from_rect, to_rect):
    ret = Vector2(point.x, point.y)
    # translate from_rect to origin
    ret -= from_rect.left_bottom
    # scale
    ret.x *= to_rect.width / from_rect.width
    ret.y *= to_rect.height / from_rect.height
    # translate origin to to_rect
    ret += to_rect.left_bottom
    return ret

def RectTransformRect(rect, from_rect, to_rect):
    left_bottom = RectTransform(rect.left_bottom, from_rect, to_rect)
    width = rect.width * to_rect.width / from_rect.width
    height = rect.height * to_rect.height / from_rect.height
    return Rect2(left_bottom.x, left_bottom.y, width, height)

def VectorsToRect(point_1, point_2):
    return Rect2(min(point_1.x, point_2.x),
                 min(point_1.y, point_2.y),
                 abs(point_1.x - point_2.x),
                 abs(point_1.y - point_2.y))

########################################################
# Unit tests


def main():
    assert (Vector2(1, 0.5) + Vector2(2.3, 1.2)) == Vector2(3.3, 1.7)
    assert (Vector2(3, 0) - Vector2(1, 1)) == Vector2(2, -1)
    assert (Vector2(3, 1.5) * Vector2(2, 4)) == Vector2(6, 6)
    assert (Vector2(3, 1.5) * 2) == Vector2(6, 3)
    assert (Vector2(3, 1.5) * 1.5) == Vector2(4.5, 2.25)
    assert (2 * Vector2(3, 1.5)) == Vector2(6, 3)
    assert (1.5 * Vector2(3, 1.5)) == Vector2(4.5, 2.25)
    assert (Vector2(3, 1.5) / 1.5) == Vector2(2, 1)
    assert (Vector2(3, 1.5) / 2) == Vector2(1.5, 0.75)
    assert (Vector2(3, 1.5) / 1.5) == Vector2(2, 1)
    
    v = Vector2(2, 0)
    v.Normalize()
    assert (v.x == 1.0)
    
    v = Vector2(0, 2)
    v.Normalize()
    assert (v.y == 1.0)
    
    r = Rect2(0, 0, 2, 3)
    r.Translate(Vector2(2, 3))
    assert r.left == 2
    assert r.bottom == 3
    assert r.right == 4
    assert r.top == 6
    assert r.Contains(Vector2(2.5, 4.5))
    
    print 'All tests successful'

if __name__ == '__main__':
    main()